#!/usr/bin/env python
# encoding: utf-8


"""
@file: jiesanjiaohanshu.py
@time: 2017/1/11 下午3:35
"""
# 解三角函数
from functools import reduce
from mathsolver.functions.base import *
from sympy import sin, cos, tan, degree, expand, solveset
from mathsolver.functions.budengshi import common_opers as co
from mathsolver.functions.sanjiao import sanjiao_utils
from itertools import chain
from mathsolver.functions.budengshi.ineq_constants import INEQ_SEARCH_KEY
from mathsolver.functions.budengshi.jiebudengshi import JieBuDengShi
from mathsolver.functions.sanjiao.huajian import trig_simplify
from mathsolver.functions.sanjiao import sanjiao_utils as su
from mathsolver.functions.sanjiao.sanjiaofangcheng import JieSanJiaoFangCheng
from sympy.sets.fancysets import Integers


# 接三角方程
# Input1 paramer1:BaseEq()/BasePoly
# Input2 paramer1:BaseEq()/BasePoly; paramer2 BaseInterval
class MatheJieSanJiaoHanShhu(BaseFunction):
    def solver(self, *args):
        self.label.add('解三角方程')
        symb_intl = None
        x_symbol = None
        if len(args) == 1:  # Input1
            if isinstance(args[0], BaseEq) or isinstance(args[0], BaseSinEq):
                left_expr, right_expr = args[0].sympify()
            elif isinstance(args[0], BasePoly):
                left_expr = sympify('y')
                right_expr = args[0].sympify()
            else:
                left_expr = sympify('y')
                right_expr = sympify(args[0])
        elif len(args) == 2:
            if (isinstance(args[0], BaseEq) or isinstance(args[0], BaseSinEq)) and isinstance(args[1], BaseInter):
                left_expr, right_expr = args[0].sympify()
                symb_intl = args[1].interval
            elif isinstance(args[0], BasePoly) and isinstance(args[1], BaseInter):
                left_expr = sympify('y')
                right_expr = args[0].sympify()
                symb_intl = args[1].interval
            elif isinstance(args[0], BaseSinEq) and isinstance(args[1], BaseVariable):
                left_expr, right_expr = args[0].sympify()
                x_symbol = args[1].sympify()
            elif isinstance(args[1], Interval):
                left_expr = sympify('y')
                right_expr = sympify(args[0])
                symb_intl = args[1]
        else:
            raise Exception('Tyep Match Error')
        f = left_expr - right_expr
        if not x_symbol:
            x_symbol = list(f.free_symbols)[0]
        if self.search(x_symbol):
            symb_intl = self.search(x_symbol)
        sim_f = trig_simplify(f)
        trig_f, _ = co.split_mons_const(sim_f)
        _1, t_type, t_arg, _2 = su.simp_trig_info(trig_f)
        sim_f_expr_t_sub = sim_f.subs(t_arg, 't')
        t_results = list(list(JieSanJiaoFangCheng().solver(BaseEq([sim_f_expr_t_sub, '0'])).output[0].sympify().values())[0])
        x_results = list(map(lambda _: expand(solve(_ - sympify(t_arg), x_symbol)[0]), t_results))
        z = Integers()
        self.steps.append(
            ['由题意可知' + BaseEq([left_expr, right_expr]).printing(),
             '解集为' + new_latex(x_results) + '其中k \\in ' + new_latex(z)])
        if symb_intl:  # 如果有范围
            self.steps.append(['因为 ' + new_latex(x_symbol), '\\in ' + new_latex(symb_intl)])
            x_results = list(co.flatten(map(lambda _: su.expr_value_list(_, symb_intl), x_results)))
            self.steps.append(['所以 x的值为', new_latex(FiniteSet(*x_results))])
        self.output.append(BaseSymbolValue({x_symbol: FiniteSet(*x_results)}))
        return self


# 方程2cosx+1=0的解集是().
class JieSanJiaoHanShu001(BaseFunction):
    def solver(self, *args):
        self.label.add('解三角方程')
        l_expr, r_expr = args[0].sympify()
        f = l_expr - r_expr
        v = list(f.free_symbols)[0]
        tmp_f = f.subs(cos(v), 1).subs(sin(v), 1)
        if not tmp_f.is_real:
            raise Exception('Type Match Error')
        solve_v = solveset(f)
        self.steps.append(['答案为:', new_latex(solve_v)])
        if self.search(INEQ_SEARCH_KEY):
            ineqs = co.to_base(self.search(INEQ_SEARCH_KEY), BaseIneqs)
            ineq_intl = JieBuDengShi().solver(ineqs).output[0].sympify().values()[0]
            solve_expr = solve_v.args[0].args[1]
            self.steps.append(['因为 ' + new_latex(v) + ' \\in ' + new_latex(ineq_intl), ''])
            x_values = sanjiao_utils.expr_value_list(solve_expr, ineq_intl)
            self.steps.append(['所以 ' + new_latex(v) + '值为' + new_latex(x_values[0]), ''])
            self.output.append(BaseSymbolValue({v: x_values[0]}))
        else:
            self.output.append(BaseSymbolValue({v: solve_v}))
        return self


# 若sin(\\frac{π}{2}x+\\frac{π}{4})=\\frac{\\sqrt{2}}{2},x∈(-2,2),则x=().
class JieSanJiaoHanShu002(BaseFunction):
    def solver(self, *args):
        self.label.add('解三角方程')
        l_expr, r_expr = args[0].sympify()
        f = l_expr - r_expr
        v = list(f.free_symbols)[0]
        trig_f, const = co.split_mons_const(f)
        arg = sanjiao_utils.trig_arg(trig_f)
        trig_type = sanjiao_utils.trig_type(trig_f)
        if self.search(v):
            intl = self.search(v)
            self.steps.append(['\\because %s \\in' % new_latex(v), new_latex(intl)])
            arg_domain = co.func_domain(arg, {str(v): intl})
            self.steps.append(['设 v = ' + new_latex(arg), '\\in' + new_latex(arg_domain)])
            self.steps.append(['\\therefore u = ' + new_latex(trig_type('v')), ''])
            new_f = trig_type('v') + const
            values = solve(new_f)
            new_vfs = map(lambda tmp_v: BaseEq([arg, tmp_v]), values)
            new_vs = map(lambda tmp_v: solve(arg - tmp_v)[0], values)
            fs_print = reduce(lambda vf1, vf2: vf1.printing() + '或' + vf2.printing(), new_vfs)
            vs_print = reduce(lambda v1, v2: new_latex(v) + '=' + new_latex(v1) + '或' + new_latex(v) + '=' + new_latex(v2), new_vs)
            self.steps.append(['\\therefore', fs_print])
            self.steps.append(['解得: ', vs_print])
            vald_vs = list(filter(lambda tmp_v: tmp_v in intl, new_vs))
            if len(vald_vs) == 1:
                self.steps.append(['故答案为:', new_latex(vald_vs[0])])
                self.output.append(BaseSymbolValue({v: vald_vs[0]}))
            else:
                vald_vs_print = reduce(lambda v1, v2: new_latex(v) + '=' + new_latex(v1) + '或' + new_latex(v) + '=' + new_latex(v2),
                                       vald_vs)
                self.steps.append([vald_vs_print, ''])
                self.output.append(BaseSymbolValue({v: vald_vs}))
        else:
            self.steps.append(['设 v = ' + new_latex(arg), ''])
            self.steps.append(['\\therefore u = ' + new_latex(trig_type('v')), ''])
            new_f = trig_type('v') + const
            values = solve(new_f)
            new_vfs = list(map(lambda tmp_v: BaseEq([arg, tmp_v]), values))
            new_vs = list(map(lambda tmp_v: solve(arg - tmp_v)[0], values))
            fs_print = reduce(lambda vf1, vf2: vf1.printing() + '或' + vf2.printing(), new_vfs)
            vs_print = reduce(lambda v1, v2: new_latex(v) + '=' + new_latex(v1) + '或' + new_latex(v) + '=' + new_latex(v2), new_vs)
            self.steps.append(['\\therefore', fs_print])
            self.steps.append(['解得: ', vs_print])
            if len(new_vs) == 1:
                self.steps.append(['故答案为:', new_latex(new_vs[0])])
                self.output.append(BaseSymbolValue({v: new_vs[0]}))
            else:
                vald_vs_print = reduce(lambda v1, v2: new_latex(v) + '=' + new_latex(v1) + '或' + new_latex(v) + '=' + new_latex(v2),
                                       new_vs)
                self.steps.append([vald_vs_print, ''])
                self.output.append(BaseSymbolValue({v: new_vs}))
        return self


# 方程2sin^{2}x+3sinx-2=0的解集是().
class JieSanJiaoHanShu003(BaseFunction):
    @staticmethod
    def print_values(values, v_name):
        v_symbol = sympify(v_name)
        return reduce(lambda v1, v2: new_latex(v_symbol) + '=' + new_latex(v1) + '或' + new_latex(v_symbol) + '=' + new_latex(v2),
                      values)

    def solver(self, *args):
        l_expr, r_expr = args[0].sympify()
        f = l_expr - r_expr
        v = list(f.free_symbols)[0]
        t_symbol = 't'
        sin_sub_f = f.subs(sin(v), t_symbol)
        cos_sub_f = f.subs(cos(v), t_symbol)
        tan_subs_f = f.subs(tan(v), t_symbol)
        if sin_sub_f != f:
            sub_f = sin_sub_f
            sub_type = sin
        elif cos_sub_f != f:
            sub_f = cos_sub_f
            sub_type = cos
        elif tan_subs_f != f:
            sub_f = tan_subs_f
            sub_type = tan
        else:
            raise Exception('Type Match Error')
        if degree(sub_f) == 1:
            raise Exception('Type Match Error')
        self.steps.append(['令 %s=%s' % (new_latex(f), new_latex(sub_f)), 't \\in ' + new_latex(Interval.open(-1, 1))])
        t_values = solve(sub_f)
        t_values = list(filter(lambda t_v: t_v in Interval(-1, 1), t_values))
        if len(t_values) == 1:
            self.steps.append(['解的: t=', new_latex(t_values[0])])
            solve_set = solve(t_values[0] - sub_type(v))
            values = map(lambda s: sympify('2*k*pi') + s, solve_set)
            self.steps.append(['\\therefore ', JieSanJiaoHanShu003.print_values(values, v)])
            self.output.append(BaseSymbolValue({v: values}))
        else:
            self.steps.append(['解得: ', JieSanJiaoHanShu003.print_values(t_values, 't')])
            self.steps.append(['当t = ', new_latex(t_values[0]) + '时'])
            solve_set = solve(t_values[0] - sub_type(v))
            values1 = map(lambda s: sympify('2*k*pi') + s, solve_set)
            self.steps.append(['\\therefore ', JieSanJiaoHanShu003.print_values(values1, v)])
            self.steps.append(['当t = ', new_latex(t_values[1]) + '时'])
            solve_set = solve(t_values[1] - sub_type(v))
            values2 = map(lambda s: sympify('2*k*pi') + s, solve_set)
            self.steps.append(['\\therefore ', JieSanJiaoHanShu003.print_values(values2, v)])
            values = chain(values1, values2)
            self.steps.append(['所以求得解集', JieSanJiaoHanShu003.print_values(values, v)])
            self.output.append(BaseSymbolValue({v: values}))
        return self


class JieSanJiaoHanShu(BaseFunction):
    CLS = [MatheJieSanJiaoHanShhu, JieSanJiaoHanShu001, JieSanJiaoHanShu002, JieSanJiaoHanShu003]

    def solver(self, *args):
        solve_r = None
        for cl in JieSanJiaoHanShu.CLS:
            try:
                solve_r = cl(verbose=True)
                solve_r.known = self.known
                solve_r = solve_r.solver(*args)
                solve_r.label.add('解三角方程')
                break
            except Exception:
                solve_r = None
        if not solve_r:
            raise 'try fail'
        return solve_r
